using System;
using System.Windows.Forms;
using iTunesUtil.Properties;
using System.IO;
using System.Collections.Generic;
using iTunesExport.Parser;
using System.Text;

namespace iTunesUtil
{   
    public partial class ExportDlg : Form
    {
        Settings set = Settings.Default;                
        string type;
        string status;
        bool bStop = false;
        IEnumerable<TrackCollection> dict;
        long maxNoFiles;
        long maxDirSizeByte;

        #region utilities
        private void CreateToolTip(Control ctrl, string msg)
        {
            ToolTip tt = new ToolTip();
            tt.IsBalloon = true;
            tt.SetToolTip(ctrl, msg);            
        }
        private void CreateTooltips()
        {
            CreateToolTip(checkBoxRandom, "Random order of tracks ?");
            CreateToolTip(buttonOptions, "Set options for file names, size ...");
            CreateToolTip(buttonNew, "Create new collection");
            CreateToolTip(buttonDir, "Browse for output directory");
            CreateToolTip(buttonCopy, "Copy collection to folder");            
            CreateToolTip(buttonCancel, "Leave this dialog");            
        }
        private void SetTitle()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format("Export iTunes '{0}'", type));
            if (OptionsDlg.MaxNoFiles > 0)
                sb.Append(string.Format(" (max. {0} files)", OptionsDlg.MaxNoFiles));
            if (OptionsDlg.MaxDirSizeMB > 0)
                sb.Append(string.Format(" (max. {0} MB)", OptionsDlg.MaxDirSizeMB));
            this.Text = sb.ToString();
        }
        TrackCollection GetSelectedTrackCollection()
        {
            if (comboBoxPlayList.SelectedIndex == -1)
            {
                return null;
            }
            return (TrackCollection)comboBoxPlayList.Items[comboBoxPlayList.SelectedIndex];
        }
        private void EnableControls(bool state)
        {
            buttonStop.Visible = !state;
            buttonStop.Enabled = !state;
            progressBar.Visible = !state;

            buttonCopy.Enabled = state;
            buttonCancel.Enabled = state;
            buttonDir.Enabled = state;
            buttonOptions.Enabled = state;
            buttonNew.Enabled = state;

            buttonCopy.Visible = state;
            buttonCancel.Visible = state;
            buttonDir.Visible = state;
            buttonOptions.Visible = state;
            buttonNew.Visible = state;

            comboBoxPlayList.Enabled = state;
            exportDirectory.Enabled = state;
            checkBoxRandom.Enabled = state;

        }
        public bool CheckDirectory(string dir, bool delContent)
        {
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
                return Directory.Exists(dir);
            }

            DirectoryInfo dirInfo = new DirectoryInfo(dir);
            int noSubDirs = dirInfo.GetDirectories().Length;
            int noFiles = dirInfo.GetFiles().Length;

            if (noSubDirs == 0 && noFiles == 0)
                return true;

            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format("'{0}' has ", dir));
            if (noSubDirs > 0)
            {
                sb.Append(string.Format("{0} subdirectories ", noSubDirs));
                if (noFiles > 0)
                    sb.Append("and ");
            }
            if (noFiles > 0)
                sb.Append(string.Format("{0} files ", noFiles));
            sb.Append(". Please delete manually !");

            string caption = "Directory is not empty";
            MessageBox.Show(sb.ToString(), caption, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return false;
        }     
        #endregion

        public ExportDlg(IEnumerable<TrackCollection> dict, string type)
        {
            this.dict = dict;
            this.type = type;
            InitializeComponent();            
            groupBoxSource.Text = type;
            checkBoxRandom.Checked = set.ExportRandom;
            maxNoFiles = OptionsDlg.MaxNoFiles;
            maxDirSizeByte = OptionsDlg.MaxDirSizeMB;

            foreach (TrackCollection tc in dict)
            {
                if (tc.Count > 0)
                {
                    if (tc.Name == set.ExportDirSelectedPlaylist)
                    {
                        tc.GetInfo();
                        comboBoxPlayList.SelectedIndex = comboBoxPlayList.Items.Add(tc);
                    }
                    else
                        comboBoxPlayList.Items.Add(tc);                    
                }
            }
            if (comboBoxPlayList.SelectedIndex == -1)
                comboBoxPlayList.SelectedIndex = 0;

            SetTitle();                                     
        }

        bool ShouldBreak(long actSize, long actTrackNo)
        {
            if (bStop)
            {                
                return true;
            }               
            if (maxDirSizeByte > 0 && actSize > maxDirSizeByte) 
            {
                return true;
            }
            if (maxNoFiles > 0 && actTrackNo > maxNoFiles)
            {             
                return true;
            }            
            return false;
        }
                                   
        private void Copy(TrackCollection tc, string expDir)
        {           
            long actTrackNo = 1;            
            long actSize = 0;

            ExportFileFormatter formatter = new ExportFileFormatter(expDir);
            foreach(Track t in tc.Tracks)
            {
                FileInfo fi = new FileInfo(t.Location);
                if (!fi.Exists)
                    continue;
                actSize += fi.Length;

                if (ShouldBreak(actSize, actTrackNo))
                    break;

                PerformProgressStep(string.Format("{0}/{1} {2}", actTrackNo, maxNoFiles, t.Name));
                File.Copy(t.Location, formatter.Generate(t, actTrackNo++));                
            }
            status = string.Format("Copied {0} of {1} tracks with {2}MB", actTrackNo - 1, maxNoFiles, actSize >> 20);

            Invoke(new MethodInvoker(delegate()
            {
                EnableControls(true);                
                buttonCancel.Focus();
                textBox1.Text = status;
                
            }));
        }
             
        #region button handler
        private void OnOptionsChanged(object sender, EventArgs e)
        {
            maxNoFiles = OptionsDlg.MaxNoFiles;
            maxDirSizeByte = OptionsDlg.MaxDirSizeMB << 20;
         
            TrackCollection tc = GetSelectedTrackCollection();
            if (tc == null)
                return;

            Cursor = Cursors.WaitCursor;
            exportDirectory.Text = Path.Combine(Settings.Default.ExportDir, ExportFileFormatter.FilterInvalidPathCharacters(tc.Name));
            tc.GetInfo();

            groupBoxSource.Text = string.Format("{0} : {1} Files {2} MB", tc.Name, tc.Count, tc.Size);

            if (tc.MissingTracks > 0)
                groupBoxSource.Text += string.Format(" {0} missing tracks", tc.MissingTracks);                

            Cursor = Cursors.Default;
        }              
        private void OnButtonCopy(object sender, EventArgs e)
        {
            TrackCollection tc = GetSelectedTrackCollection();
            if (tc == null)
                return;
            
            if (!CheckDirectory(exportDirectory.Text, set.ExportDirClear))
                return;
                        
            EnableControls(false);
            status = string.Empty;
            bStop = false;

            if (maxNoFiles < 0)
                maxNoFiles = tc.Count;
            
            progressBar.Maximum = (int) Math.Min(tc.Count, maxNoFiles);            
            progressBar.Value = 0;


            if (checkBoxRandom.Checked)
                tc = tc.Randomize();

            new Action<TrackCollection, string>(Copy).BeginInvoke(tc, exportDirectory.Text, null, null); 
           
        }      
        private void OnButtonStop(object sender, EventArgs e)
        {
            bStop = true;
        }        
        private void OnButtonNew(object sender, EventArgs e)
        {
            CombineCollectionsDlg dlg = new CombineCollectionsDlg(dict,this.type);
            if (dlg.ShowDialog() == DialogResult.OK && dlg.Collection != null)
            {
                comboBoxPlayList.SelectedIndex = comboBoxPlayList.Items.Add(dlg.Collection);
                OnOptionsChanged(sender, e);
            }
        }
        private void OnButtonOptions(object sender, EventArgs e)
        {
            new OptionsDlg().ShowDialog();
            OnOptionsChanged(this, new EventArgs());
            SetTitle();
        }
        private void OnButtonDir(object sender, EventArgs e)
        {
            Program.BrowseForFolder(exportDirectory, "Select Export Directory", true);
        }        
        private void OnButtonExit(object sender, EventArgs e)
        {
            set.ExportRandom = checkBoxRandom.Checked;
            set.Save();
        }
        #endregion


        private void PerformProgressStep(string msg)
        {
            if (this.InvokeRequired == false)
            {
                progressBar.PerformStep();
                textBox1.Text = msg;
                return;
            }
            Invoke(new Action<string>(PerformProgressStep), new object[] { msg });
        }
    }
}